//MountManager - the program for easy mounting of storage devices in Linux
//Copyright (C) 2007-2008 Tikhonov Sergey
//
//This file is part of MountManager Gui
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QAction>
#include <QtGui/QStatusBar>
#include <QtGui/QApplication>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QFileDialog>
#include <QtGui/QLabel>
#include <QtGui/QCheckBox>
#include <QtGui/QPushButton>
#include <QtGui/QDockWidget>
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QTextStream>
#include <QDesktopServices>
#include <QtCore/QUrl>
#include "../core/diskcore.h"
#include "centralwidget.h"
#include "mainwindow.h"
#include "const.h"
#include "manual.h"
#include "aboutprogramdialog.h"
#include "usbmanager.h"
#include "popupwindow.h"
#include "menu.h"
#include "trayicon.h"
#include "restorationsystem.h"
#include "pluginsmanager.h"
#include "usbwizard.h"
#include "plugininterface.h"


MainWindow::MainWindow() {
	core = new DiskCore(BACKUPS_PATH);
	popupWindow = new PopupWindow;
	centralWidget = new CentralWidget(core,popupWindow);
	setCentralWidget(centralWidget);
	manual = new Manual;
	aboutProgramDialog = new AboutProgramDialog(this);
	
	usbManager = new UsbManager(popupWindow,this);
	usbManager->getWizard()->setUsbDevices(centralWidget->usbDevices());
	
	restorationSystem = new RestorationSystem(core,this);
	pluginsManager = new PluginsManager(this);

	trayMenu = new Menu(true);
	trayMenu->setHeaderIcon(QIcon(PROGRAM_ICON_PATH));
	trayMenu->setHeaderText(PROGRAM_NAME);
	
	trayIcon = new TrayIcon;
	trayIcon->setContextMenu(trayMenu);
	trayIcon->show();

	// Creation of apply dialog
	
	applyDialog = new QDialog(this);

	QLabel *pixmapLabel = new QLabel;
	pixmapLabel->setPixmap(QPixmap(PROGRAM_ICON_PATH));

	QLabel *textLabel = new QLabel(tr("When you click on \"Ok\" button, the program will try to replace contents of the configuration file /etc/fstab and try to mount all devices with specified options. If you start program without root rights, the program will save configuration file in you home directory and you should replace /etc/fstab content on it by yourself."));
	textLabel->setWordWrap(true);
	textLabel->setAlignment(Qt::AlignTop);
	
	dontShowApplyDialog = new QCheckBox(tr("Don't show this message"));
	
	QPushButton *closeButton = new QPushButton(tr("Close"));
	connect(closeButton,SIGNAL(clicked()),applyDialog,SLOT(hide()));
	
	QHBoxLayout *bottomLayout = new QHBoxLayout;
	bottomLayout->addStretch();
	bottomLayout->addWidget(closeButton);
	bottomLayout->addStretch();

	QVBoxLayout *rightLayout = new QVBoxLayout;
	rightLayout->addWidget(textLabel);
	rightLayout->addWidget(dontShowApplyDialog);
	rightLayout->addStretch();
	
	QHBoxLayout *topLayout = new QHBoxLayout;
	topLayout->addWidget(pixmapLabel);
	topLayout->addLayout(rightLayout,1);
	
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addLayout(topLayout);
	mainLayout->addLayout(bottomLayout);
	applyDialog->setLayout(mainLayout);
	applyDialog->setWindowTitle(tr("Information"));
	
	// Partition menu
	partitionMenu = menuBar()->addMenu("&" + tr("Partition"));

	mountAllAction = new QAction(this);
	mountAllAction->setText(tr("Mount all resources"));
	mountAllAction->setIcon(QIcon(ICONS_PATH"mount.png"));
	
	unmountAllAction = new QAction(this);
	unmountAllAction->setText(tr("Unmount all resources"));
	unmountAllAction->setIcon(QIcon(ICONS_PATH"umount.png"));
		
	quitAction = new QAction(partitionMenu);
	quitAction->setText(tr("Quit"));
	quitAction->setShortcut(QKeySequence("Ctrl+Q"));
	quitAction->setStatusTip(tr("Quit"));
	quitAction->setIcon(QIcon(ICONS_PATH"quit.png"));
	
	saveConfigFileAction = new QAction(partitionMenu);
	saveConfigFileAction->setText(tr("Save configuration file"));
	saveConfigFileAction->setStatusTip(tr("Save configuration file generated by the program as"));
	saveConfigFileAction->setIcon(QIcon(ICONS_PATH"save_as.png"));
	
	applyAction = new QAction(partitionMenu);
	applyAction->setText(tr("Apply"));
	applyAction->setStatusTip(tr("Replace configuration file of the system on generated by the program"));
	applyAction->setIcon(QIcon(ICONS_PATH"apply.png"));

	partitionMenu->addAction(applyAction);
	partitionMenu->addSeparator();
	partitionMenu->addAction(saveConfigFileAction);
	partitionMenu->addSeparator();
	foreach (QAction *action,centralWidget->actions())
		partitionMenu->addAction(action);
	partitionMenu->addSeparator();
	partitionMenu->addAction(quitAction);
	
	// Tools menu
	toolsMenu = menuBar()->addMenu("&" + tr("Tools"));
	
	restorationSystemAction = new QAction(toolsMenu);
	restorationSystemAction->setText(tr("Restoration system"));
	restorationSystemAction->setStatusTip(tr("Back up to last content of configuration file"));
	restorationSystemAction->setIcon(QIcon(ICONS_PATH"backward.png"));
	
	usbManagerAction = new QAction(toolsMenu);
	usbManagerAction->setText(tr("USB Manager"));
	usbManagerAction->setStatusTip(tr("Create rules for Udev"));
	usbManagerAction->setIcon(QIcon(ICONS_PATH"usb_disk.png"));
	
 	usbWizardAction = new QAction(toolsMenu);
 	usbWizardAction->setText(tr("USB Wizard"));
 	usbWizardAction->setStatusTip(tr("Configure usb devices with help of the program"));
 	usbWizardAction->setIcon(QIcon(ICONS_PATH"wizard.png"));

	pluginsManagerAction = new QAction(toolsMenu);
	pluginsManagerAction->setText(tr("Plugins manager"));
	pluginsManagerAction->setStatusTip(tr("Enable or disable plugins for the program"));
	pluginsManagerAction->setIcon(QIcon(ICONS_PATH"plugin_manager.png"));
	
	toolsMenu->addAction(pluginsManagerAction);
	toolsMenu->addAction(restorationSystemAction);
	toolsMenu->addAction(usbManagerAction);
 	toolsMenu->addAction(usbWizardAction);
	
	// Plugins menu	
	pluginsMenu = menuBar()->addMenu("&" + tr("Plugins"));
	
	// Help menu
	helpMenu = menuBar()->addMenu("&" + tr("Help"));

	documentationAction = new QAction(helpMenu);
	documentationAction->setText(tr("Manual"));
	documentationAction->setShortcut(QKeySequence("F1"));
	documentationAction->setStatusTip(tr("Read documentation of the program"));
	documentationAction->setIcon(QIcon(ICONS_PATH"manual.png"));

	aboutProgramAction = new QAction(helpMenu);
	aboutProgramAction->setText(tr("About the program"));
	aboutProgramAction->setStatusTip(tr("Read information about the program"));
	aboutProgramAction->setIcon(QIcon(PROGRAM_ICON_PATH));

	helpMenu->addAction(documentationAction);
	helpMenu->addSeparator();

	// Links menu
	linksMenu = new QMenu(tr("Internet links"));
	linksMenu->setIcon(QIcon(ICONS_PATH"web.png"));
	
	reportBugAction = new QAction(linksMenu);
	reportBugAction->setText(tr("Report bugs"));
	reportBugAction->setIcon(QIcon(ICONS_PATH"send.png"));
	
	developerAction = new QAction(linksMenu);
	developerAction->setText(tr("Developer's e-mail"));
	developerAction->setIcon(QIcon(ICONS_PATH"send.png"));
	
	homePageAction = new QAction(linksMenu);
	homePageAction->setText(tr("Project home page"));
	homePageAction->setIcon(QIcon(ICONS_PATH"web.png"));
	
	supportPageAction = new QAction(linksMenu);
	supportPageAction->setText(tr("Support the organization"));
	supportPageAction->setIcon(QIcon(ICONS_PATH"web.png"));

	linksMenu->addAction(developerAction);
	linksMenu->addAction(reportBugAction);
	linksMenu->addAction(homePageAction);
	linksMenu->addAction(supportPageAction);
	
	helpMenu->addMenu(linksMenu);

	helpMenu->addSeparator();
	helpMenu->addAction(aboutProgramAction);
	// Tray menu
	trayMenu->addAction(aboutProgramAction);
	trayMenu->addAction(quitAction);
	
	// Status bar
	statBar = statusBar();

	// Actions connections
	connect(mountAllAction,SIGNAL(triggered()),core,SLOT(mountAll()));
	connect(unmountAllAction,SIGNAL(triggered()),core,SLOT(unmountAll()));
	connect(quitAction,SIGNAL(triggered()),this,SLOT(quit()));
	connect(documentationAction,SIGNAL(triggered()),manual,SLOT(show()));
	connect(aboutProgramAction,SIGNAL(triggered()),aboutProgramDialog,SLOT(exec()));
	connect(usbManagerAction,SIGNAL(triggered()),usbManager,SLOT(show()));
	connect(saveConfigFileAction,SIGNAL(triggered()),this,SLOT(saveConfig()));
	connect(restorationSystemAction,SIGNAL(triggered()),restorationSystem,SLOT(show()));
	connect(pluginsManagerAction,SIGNAL(triggered()),pluginsManager,SLOT(show()));
	connect(usbWizardAction,SIGNAL(triggered()),this,SLOT(updateWizard()));
	connect(usbWizardAction,SIGNAL(triggered()),usbManager->getWizard(),SLOT(exec()));
	connect(applyAction,SIGNAL(triggered()),this,SLOT(apply()));
	connect(trayIcon,SIGNAL(hideOrShowSignal()),this,SLOT(hideOrShow()));
	connect(centralWidget,SIGNAL(showTrayMessage(const QString&,const QString&)),this,SLOT(showTrayMessage(const QString&,const QString&)));
	connect(centralWidget,SIGNAL(setUsbDeviceAutomount(DiskDevice *)),this,SLOT(setUsbDeviceAutomount(DiskDevice *)));
	connect(centralWidget,SIGNAL(deviceWasAdded(DiskDevice *)),this,SLOT(deviceAdded(DiskDevice *)));
	connect(centralWidget,SIGNAL(deviceWasRemoved(DiskDevice *)),this,SLOT(deviceRemoved(DiskDevice *)));
	connect(pluginsManager,SIGNAL(pluginEnabled(int)),this,SLOT(enablePlugin(int)));
	connect(pluginsManager,SIGNAL(pluginDisabled(int)),this,SLOT(disablePlugin(int)));
	connect(this,SIGNAL(started()),centralWidget,SIGNAL(started()));
	connect(centralWidget,SIGNAL(goToSupportPage()),this,SLOT(goToSupportPage()));

	connect(reportBugAction,SIGNAL(triggered()),this,SLOT(reportBug()));
	connect(developerAction,SIGNAL(triggered()),this,SLOT(sendLetterToDeveloper()));
	connect(homePageAction,SIGNAL(triggered()),this,SLOT(goToHomepage()));
	connect(supportPageAction,SIGNAL(triggered()),this,SLOT(goToSupportPage()));

	
	setWindowTitle(PROGRAM_NAME_WITH_VERSION);
	setWindowIcon(QIcon(PROGRAM_ICON_PATH));
	loadPlugins();
	loadSettings();
	show();
	emit (started());
}

MainWindow::~MainWindow() {
	
	delete core;
	delete centralWidget;
	delete manual;
	delete applyDialog;
	delete pluginsManager;

	delete trayMenu;
	delete trayIcon;
	
	delete mountAllAction;
	delete unmountAllAction;

	delete partitionMenu;
	delete pluginsMenu;
	delete toolsMenu;
	delete linksMenu;
	delete helpMenu;
}

void MainWindow::saveSettings() {
	QSettings settings(ORGANIZATION,PROGRAM_NAME);
	settings.setValue("MainWindow/Position",pos());
	settings.setValue("MainWindow/Size",size());
	settings.setValue("MainWindow/State",saveState());
	centralWidget->saveSettings();
	manual->saveSettings();
	restorationSystem->saveSettings();
	pluginsManager->saveSettings();
}

void MainWindow::loadSettings() {
	QSettings settings(ORGANIZATION,PROGRAM_NAME);
	isFirstStart = !settings.contains("MainWindow/Size");
	resize(settings.value("MainWindow/Size",QSize(1000,600)).toSize());
	move(settings.value("MainWindow/Position",QPoint(0,0)).toPoint());
	restoreState(settings.value("MainWindow/State").toByteArray());
	centralWidget->loadSettings();
	manual->loadSettings();
	restorationSystem->loadSettings();
}

void MainWindow::quit() {
	saveSettings();
	qApp->quit();
}

void MainWindow::closeEvent(QCloseEvent *) {
	quit();
}

void MainWindow::saveConfig() {
	QString filePath = QFileDialog::getSaveFileName(this,tr("Save config file"),QDir::homePath());
	if (filePath.isEmpty())
		return;
	QFile file(filePath);
	file.open(QIODevice::WriteOnly);
	QTextStream stream(&file);
	stream << centralWidget->currentFstabText();
}

void MainWindow::apply() {
	QSettings settings(ORGANIZATION,PROGRAM_NAME);
	if (settings.value("MainWindow/showApplyDialog",true).toBool()) {
		applyDialog->exec();
		settings.setValue("MainWindow/showApplyDialog",!dontShowApplyDialog->isChecked());
	}
	QString text = centralWidget->currentFstabText();
	if (core->setFstabContent(text) == 0) {
		restorationSystem->addBackup(text);
		restorationSystem->updateTextBrowser();
		centralWidget->showMessageWithActions(tr("Configuration file was replaced by new content succesfully."),
												QList<QAction *>() << mountAllAction << unmountAllAction);
	} else {
		QFile file(QDir::homePath() + "/fstab");
		file.open(QIODevice::WriteOnly);
		QTextStream stream(&file);
		stream << text;
		centralWidget->showWarning(tr("Cannot save configuration file - it is saved in %1").arg(QDir::homePath() + "/fstab"));
	}
}

void MainWindow::hideOrShow() {
	setVisible(isHidden());
}

void MainWindow::showTrayMessage(const QString& title,const QString& message) {
	trayIcon->showMessage(title,message);
}

void MainWindow::loadPlugins() {
	int pluginId = -1;
	foreach (MountManagerPlugin *plugin,pluginsManager->plugins()) {
		pluginId++;
		if (plugin == 0)
			continue;
		enablePlugin(pluginId);
	}
}

void MainWindow::enablePlugin(int pluginIndex) {
	MountManagerPlugin *enabledPlugin = pluginsManager->plugins()[pluginIndex];
	enabledPlugin->setParent(centralWidget);
	if (enabledPlugin->dockWidget() != 0) {
		switch(enabledPlugin->dockWidget()->allowedAreas()) {
			case Qt::AllDockWidgetAreas:
				addDockWidget(Qt::RightDockWidgetArea,enabledPlugin->dockWidget());
				break;
			case Qt::RightDockWidgetArea:
				addDockWidget(Qt::RightDockWidgetArea,enabledPlugin->dockWidget());
				break;
			case Qt::LeftDockWidgetArea:
				addDockWidget(Qt::LeftDockWidgetArea,enabledPlugin->dockWidget());
				break;
			case Qt::TopDockWidgetArea:
				addDockWidget(Qt::TopDockWidgetArea,enabledPlugin->dockWidget());
				break;
			case Qt::BottomDockWidgetArea:
				addDockWidget(Qt::BottomDockWidgetArea,enabledPlugin->dockWidget());
				break;
		}
		if (!isFirstStart)
			enabledPlugin->dockWidget()->show();
		else
			enabledPlugin->dockWidget()->hide();
	}
	if (enabledPlugin->dialog() != 0)
		enabledPlugin->dialog()->setParent(this,Qt::Dialog);
	if (enabledPlugin->menu() != 0)
		pluginsMenu->addMenu(enabledPlugin->menu());
	if (enabledPlugin->toolBar() != 0)
		addToolBar(enabledPlugin->toolBar());

	foreach (QAction *action,enabledPlugin->menuActions())
		pluginsMenu->addAction(action);

	centralWidget->emitSignalsForPlugins();
}

void MainWindow::disablePlugin(int pluginIndex) {
	MountManagerPlugin *disabledPlugin = pluginsManager->plugins()[pluginIndex];
	if (disabledPlugin->dockWidget() != 0)
		removeDockWidget(disabledPlugin->dockWidget());
	if (disabledPlugin->dialog() != 0)
		disabledPlugin->dialog()->hide();
	if (disabledPlugin->menu() != 0)
		disabledPlugin->menu()->hide();
	if (disabledPlugin->toolBar() != 0)
		removeToolBar(disabledPlugin->toolBar());
	foreach (QAction *action,disabledPlugin->menuActions())
		pluginsMenu->removeAction(action);
}


void MainWindow::reportBug() {
	QDesktopServices::openUrl(QUrl("http://code.google.com/p/linuxtuner/issues/entry?template=Defect%20report%20from%20user"));
}

void MainWindow::sendLetterToDeveloper() {
	QDesktopServices::openUrl(QUrl("mailto:"AUTHOR_EMAIL"?subject=About "PROGRAM_NAME));
}

void MainWindow::goToHomepage() {
	QDesktopServices::openUrl(QUrl("http://code.google.com/p/linuxtuner/"));
}

void MainWindow::goToSupportPage() {
	QDesktopServices::openUrl(QUrl("http://vialinx.org/?page_id=11"));
}

void MainWindow::deviceAdded(DiskDevice *addedDevice) {
	usbManager->getWizard()->addUsbDevice(addedDevice);
}

void MainWindow::deviceRemoved(DiskDevice *removedDevice) {
	usbManager->getWizard()->removeUsbDevice(removedDevice);
}

void MainWindow::updateWizard() {
	foreach (DiskDevice *usbDevice,centralWidget->usbDevices()) {
		usbManager->getWizard()->setMountOptionsForDevice(usbDevice,centralWidget->mountOptionsOfDevice(usbDevice));
		usbManager->getWizard()->setMountPointForDevice(usbDevice,centralWidget->mountPointOfDevice(usbDevice));
	}
}

void MainWindow::setUsbDeviceAutomount(DiskDevice *device) {
	usbManager->getWizard()->setMountOptionsForDevice(device,centralWidget->mountOptionsOfDevice(device));
	usbManager->getWizard()->setMountPointForDevice(device,centralWidget->mountPointOfDevice(device));
	usbManager->getWizard()->setDefaultDevice(device);
	usbManager->getWizard()->exec();
}
